package com.aydqyy.springbootstart.controller;

import com.aydqyy.springbootstart.entity.User;
import com.aydqyy.springbootstart.service.UserService;
import com.aydqyy.springbootstart.utils.JwtUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@ExtendWith(MockitoExtension.class)  // 使用 Mockito 扩展，替代 Spring 上下文
public class UserControllerTest3 {

    @Mock
    private UserService userService;  // 使用 Mockito 原生 @Mock 替代 @MockBean

    @InjectMocks
    private UserController userController;  // 将模拟对象注入被测试的 Controller

    private MockMvc mockMvc;

    private User user;

    @BeforeEach
    void setUp() {
        // 手动初始化 MockMvc（不依赖 Spring 上下文）
        mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
        user = new User();
        this.user.setId(1);
        this.user.setName("testUser");
        this.user.setPassword("testPassword");

    }

    @Test
    public void testRegister_UserNotExists() throws Exception {
        // 定义模拟行为
        Mockito.when(userService.getByName(anyString())).thenReturn(null);
        Mockito.when(userService.saveOrUpdate(any(User.class))).thenReturn(true);

        // 执行请求并验证结果
        mockMvc.perform(post("/user/register")
                        .param("name", "test1")
                        .param("password", "123456"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(0))
                .andExpect(jsonPath("$.message").value("操作成功"));
        verify(userService, times(1)).getByName("test1");
        verify(userService, times(1)).saveOrUpdate(any(User.class));

    }

    @Test
    public void testRegister_UserAlreadyExists() throws Exception {
        Mockito.when(userService.getByName("testUser")).thenReturn(this.user);

        mockMvc.perform(post("/user/register")
                        .param("name", "testUser")
                        .param("password", "testPassword"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(1))
                .andExpect(jsonPath("$.message").value("用户已经存在"));

        verify(userService, times(1)).getByName("testUser");
        verify(userService, never()).saveOrUpdate(any(User.class));
    }

    @Test
    public void testList() throws Exception {
        List<User> userList = new ArrayList<>();
        userList.add(this.user);
        Mockito.when(userService.list()).thenReturn(userList);

        mockMvc.perform(get("/user/list"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$[0].id").value(1))
                .andExpect(jsonPath("$[0].name").value("testUser"));
        verify(userService, times(1)).list();
    }

    @Test
    public void testLogin_IncorrectPassword() throws Exception {

        Mockito.when(userService.getByName("testUser")).thenReturn(this.user);

        mockMvc.perform(post("/user/login")
                        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                        .content("name=testUser&password=wrongPassword")) // 手动构建表单格式字符串
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.code").value(1))
                .andExpect(jsonPath("$.message").value("登录失败"));

        verify(userService, times(1)).getByName("testUser");
    }

    @Test
    public void testLogin() throws Exception {
        // 1. 配置服务层 Mock
        Mockito.when(userService.getByName("testUser")).thenReturn(this.user); // ✅ 使用具体值
        // 创建静态方法的模拟
        try (MockedStatic<JwtUtil> mockedStatic = mockStatic(JwtUtil.class)) {
            // 配置静态方法行为
            Map<String, Object> claims = new HashMap<>();
            claims.put("id", user.getId());
            claims.put("name", user.getName());
            mockedStatic.when(()->JwtUtil.genToken(claims)).thenReturn("token");
            mockMvc.perform(post("/user/login")
                            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                            .param("name", "testUser")    // ✅ 实际参数
                            .param("password", "testPassword"))
                    .andExpect(status().isOk())
                    .andExpect(jsonPath("$.code").value(0))
                    .andExpect(jsonPath("$.message").value("操作成功"))
                    .andExpect(jsonPath("$.data").value("token"));

            // 3. 验证调用（正确使用匹配器）
            verify(userService, times(1)).getByName("testUser"); // ✅ 具体值验证
            mockedStatic.verify(() -> JwtUtil.genToken(claims), times(1));

        }

    }
}
